jackspeak
A very strict and proper argument parser.
Validate string, boolean, and number options, from the command
line and the environment.
Call the jack
method with a config object, and then chain
methods off of it.
At the end, call the .parse()
method, and you'll get an object
with positionals
and values
members.
Any unrecognized configs or invalid values will throw an error.
As long as you define configs using object literals, types will
be properly inferred and TypeScript will know what kinds of
things you got.
If you give it a prefix for environment variables, then defaults
will be read from the environment, and parsed values written back
to it, so you can easily pass configs through to child processes.
Automatically generates a usage
/help
banner by calling the
.usage()
method.
Unless otherwise noted, all methods return the object itself.
USAGE
import { jack } from 'jackspeak'
const { positionals, values } = jack({ envPrefix: 'FOO' })
.flag({
asdf: { description: 'sets the asfd flag', short: 'a', default: true },
'no-asdf': { description: 'unsets the asdf flag', short: 'A' },
foo: { description: 'another boolean', short: 'f' },
})
.optList({
'ip-addrs': {
description: 'addresses to ip things',
delim: ',',
default: ['127.0.0.1'],
},
})
.parse([
'some',
'positional',
'--ip-addrs',
'192.168.0.1',
'--ip-addrs',
'1.1.1.1',
'args',
'--foo',
'-A',
])
console.log(process.env.FOO_ASDF)
console.log(process.env.FOO_FOO)
console.log(values)
console.log(process.env.FOO_IP_ADDRS)
console.log(positionals)
jack(options: JackOptions = {}) => Jack
Returns a Jack
object that can be used to chain and add
field definitions. The other methods (apart from validate()
,
parse()
, and usage()
obviously) return the same Jack object,
updated with the new types, so they can be chained together as
shown in the code examples.
Options:
-
allowPositionals
Defaults to true. Set to false
to not
allow any positional arguments.
-
envPrefix
Set to a string to write configs to and read
configs from the environment. For example, if set to MY_APP
then the foo-bar
config will default based on the value of
env.MY_APP_FOO_BAR
and will write back to that when parsed.
Boolean values are written as '1'
and '0'
, and will be
treated as true
if they're '1'
or false otherwise.
Number values are written with their toString()
representation.
Strings are just strings.
Any value with multiple: true
will be represented in the
environment split by a delimiter, which defaults to \n
.
-
env
The place to read/write environment variables. Defaults
to process.env
.
-
usage
A short usage string to print at the top of the help
banner.
-
stopAtPositional
Boolean, default false. Stop parsing opts
and flags at the first positional argument. This is useful if
you want to pass certain options to subcommands, like some
programs do, so you can stop parsing and pass the positionals
to the subcommand to parse.
Jack.heading(text: string, level?: 1 | 2 | 3 | 4 | 5 | 6)
Define a short string heading, used in the usage()
output.
Indentation of the heading and subsequent description/config
usage entries (up until the next heading) is set by the heading
level.
If the first usage item defined is a heading, it is always
treated as level 1, regardless of the argument provided.
Headings level 1 and 2 will have a line of padding underneath
them. Headings level 3 through 6 will not.
Jack.description(text: string, { pre?: boolean } = {})
Define a long string description, used in the usage()
output.
If the pre
option is set to true
, then whitespace will not be
normalized. However, if any line is too long for the width
allotted, it will still be wrapped.
Option Definitions
Configs are defined by calling the appropriate field definition
method with an object where the keys are the long option name,
and the value defines the config.
Options:
type
Only needed for the addFields
method, as the others
set it implicitly. Can be 'string'
, 'boolean'
, or
'number'
.multiple
Only needed for the addFields
method, as the
others set it implicitly. Set to true
to define an array
type. This means that it can be set on the CLI multiple times,
set as an array in the values
and it is represented in the environment as a delimited string.short
A one-character shorthand for the option.description
Some words to describe what this option is and
why you'd set it.hint
(Only relevant for non-boolean types) The thing to show
in the usage output, like --option=<hint>
validate
A function that returns false (or throws) if an
option value is invalid.default
A default value for the field. Note that this may be
overridden by an environment variable, if present.
Jack.flag({ [option: string]: definition, ... })
Define one or more boolean fields.
Boolean options may be set to false
by using a
--no-${optionName}
argument, which will be implicitly created
if it's not defined to be something else.
If a boolean option named no-${optionName}
with the same
multiple
setting is in the configuration, then that will be
treated as a negating flag.
Jack.flagList({ [option: string]: definition, ... })
Define one or more boolean array fields.
Jack.num({ [option: string]: definition, ... })
Define one or more number fields. These will be set in the
environment as a stringified number, and included in the values
object as a number.
Jack.numList({ [option: string]: definition, ... })
Define one or more number list fields. These will be set in the
environment as a delimited set of stringified numbers, and
included in the values
as a number array.
Jack.opt({ [option: string]: definition, ... })
Define one or more string option fields.
Jack.optList({ [option: string]: definition, ... })
Define one or more string list fields.
Jack.addFields({ [option: string]: definition, ... })
Define one or more fields of any type. Note that type
and
multiple
must be set explicitly on each definition when using
this method.
Actions
Use these methods on a Jack object that's already had its config
fields defined.
Jack.parse(args: string[] = process.argv): { positionals: string[], values: OptionsResults }
Parse the arguments list, write to the environment if envPrefix
is set, and returned the parsed values and remaining positional
arguments.
Jack.validate(o: any): asserts o is OptionsResults
Throws an error if the object provided is not a valid result set,
for the configurations defined thusfar.
Jack.usage(): string
Returns the compiled usage
string, with all option descriptions
and heading/description text, wrapped to the appropriate width
for the terminal.
Jack.setConfigValues(options: OptionsResults, src?: string)
Validate the options
argument, and set the default value for
each field that appears in the options.
Values provided will be overridden by environment variables or
command line arguments.
Jack.usageMarkdown(): string
Returns the compiled usage
string, with all option descriptions
and heading/description text, but as markdown instead of
formatted for a terminal, for generating HTML documentation for
your CLI.
Some Example Code
Also see the examples
folder
import { jack } from 'jackspeak'
const j = jack({
usage: 'foo [options] <files>',
})
.heading('The best Foo that ever Fooed')
.description(
`
Executes all the files and interprets their output as
TAP formatted test result data.
To parse TAP data from stdin, specify "-" as a filename.
`
)
.flag({
flag: {
short: 'f',
description: `Make the flags wave`,
default: true,
},
'no-flag': {
short: 'F',
description: `Do not wave the flags`,
},
})
.opt({
reporter: {
short: 'R',
description: 'the style of report to display',
},
})
.num({
jobs: {
short: 'j',
description: 'how many jobs to run in parallel',
default: 1,
},
})
.optList({
'node-arg': {},
})
.flagList({
debug: { short: 'd' },
})
.opt({
'output-file': {
short: 'o',
hint: 'file',
description: `Send the raw output to the specified file.`,
},
})
const { values, positionals } = j.parse(process.argv)
console.log(j.usage())
try {
j.validate(someConfig)
} catch (er) {
console.error('someConfig is not valid!', er)
}
Name
The inspiration for this module is yargs, which
is pirate talk themed. Yargs has all the features, and is infinitely
flexible. "Jackspeak" is the slang of the royal navy. This module
does not have all the features. It is declarative and rigid by design.